/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package javax.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;

/**
 * ServletResponseWrapper提供了一个简便实现类，在对ServletResponse有改动需求的时，可以重写此类，之后Response的操作都会经过重写的类.
 *
 * 实际应用场景中，有时可能会有这样的需求：需要在响应到客户端之前，对响应进行统一处理，增加或减少到达应用的数据量等，这时就可以创建一个类继承
 * HttpServletResponseWrapper，它可以对HttpServletResponse进行再封装，然后之后的请求都会经过这个类，应用接收到的请求对象也会是这个类。
 *
 * HttpServletResponseWrapper集成了ServletResponseWrapper，ServletResponseWrapper是对ServletResponse的包装，HttpServletResponseWrapper
 * 是对HttpServletResponse的包装，其实查看源码后会发现，ServletResponseWrapper和HttpServletResponseWrapper提供的API完全调用的ServletResponse
 * 和HttpServletResponse的API进行实现。在我们进行应用时，使用HttpServletResponseWrapper即可，它同时拥有ServletResponseWrapper和HttpServletResponseWrapper的功能。
 *
 *
 * Provides a convenient implementation of the ServletResponse interface that
 * can be subclassed by developers wishing to adapt the response from a Servlet.
 * This class implements the Wrapper or Decorator pattern. Methods default to
 * calling through to the wrapped response object.
 * 
 * @author 	Various
 *
 * @since	v 2.3
 *
 * @see 	ServletResponse
 *
 */

 
public class ServletResponseWrapper implements ServletResponse {
	/**
	 * ServletResponse实例.
	 */
	private ServletResponse response;
	/**
	* Creates a ServletResponse adaptor wrapping the given response object.
	* @throws IllegalArgumentException if the response is null.
	*/


	public ServletResponseWrapper(ServletResponse response) {
	    if (response == null) {
		throw new IllegalArgumentException("Response cannot be null");
	    }
	    this.response = response;
	}

	/**
	 * 获取ServletResponse实例.
	 * Return the wrapped ServletResponse object.
	 */

	public ServletResponse getResponse() {
		return this.response;
	}	
	
	
	/**
	 * 设置ServletResponse实例.
	 * Sets the response being wrapped.
	 * @throws IllegalArgumentException if the response is null.
	 */
	
	public void setResponse(ServletResponse response) {
	    if (response == null) {
		throw new IllegalArgumentException("Response cannot be null");
	    }
	    this.response = response;
	}

    /**
	 * 设置发送到客户端的响应的字符编码（MIME字符集），例如UTF-8.
	 * 如果字符编码已经由setContentType或setLocale设置，则此方法将重写它.
	 * 可以重复调用此方法来更改字符编码.如果在调用getWriter之后或在提交响应之后调用它，则此方法无效.
	 * 如果协议提供了一种方法，容器必须将用于servlet响应的编写器的字符编码传递给客户机.
	 * 在HTTP的情况下，字符编码作为文本媒体类型的Content-Type报头的一部分进行通信.
	 * 请注意，如果Servlet没有指定内容类型，则字符编码不能通过HTTP头进行通信.但是，它仍然用于对通过Servlet响应的编写器写入的文本进行编码.
	 *
	 * The default behavior of this method is to call setCharacterEncoding(String charset)
     * on the wrapped response object.
     *
     * @since 2.4
     */

    public void setCharacterEncoding(String charset) {
	this.response.setCharacterEncoding(charset);
    }

    /**
	 * 返回用于此响应中发送的正文的字符编码（MIME字符集）的名称.
	 * 字符编码可能是使用setCharacterEncoding或setContentType方法显式指定的，也可能是隐式使用setLocale方法指定的.显式规范优先于隐式规范.
	 * 在调用getWriter或在提交响应之后对这些方法的调用对字符编码没有影响.如果未指定字符编码，则返回ISO-8859-1.
	 *
	 * The default behavior of this method is to return getCharacterEncoding()
     * on the wrapped response object.
     */

    public String getCharacterEncoding() {
	return this.response.getCharacterEncoding();
	}
    
    
	/**
     * 返回ServletOuputStream用于在response中写入二进制数据.
	 *      Servlet容器不编码二进制数据.
	 *      调用ServletOutputStream的flush()方法提交response.
	 *      ServletOutputStream和PrintWriter不可同时使用.
	 *
	 * The default behavior of this method is to return getOutputStream()
     * on the wrapped response object.
     */

    public ServletOutputStream getOutputStream() throws IOException {
	return this.response.getOutputStream();
    }  
      
	/**
	 * 返回一个getWriter对象，该对象可以向客户端发送字符文本.
	 * PrintWriter使用getCharacterEncoding返回的字符编码.
	 * 如果响应的字符编码没有按照getCharacterEncoding中的描述指定（即，该方法只返回默认值ISO-8859-1），
	 *  则getWriter将其更新为ISO-8859-1.
	 * 调用PrintWriter的flush()方法提交response.
	 * PrintWriter和ServletOutputStream不可同时使用.
	 *
	 * The default behavior of this method is to return getWriter()
     * on the wrapped response object.
     */


    public PrintWriter getWriter() throws IOException {
	return this.response.getWriter();
	}
    
    /**
	 * 在HTTP响应头Content-Length中设置响应体内容的长度.
	 * The default behavior of this method is to call setContentLength(int len)
     * on the wrapped response object.
     */

    public void setContentLength(int len) {
	this.response.setContentLength(len);
    }
    
    /**
	 * 如果尚未提交响应，则设置发送到客户端的响应的内容类型.
	 * 给定的内容类型可以包括字符编码规范，例如，text/html;charset=UTF-8.
	 * 如果在调用getWriter之前调用此方法，则仅从给定的内容类型设置响应的字符编码.
	 * 可以重复调用此方法来更改内容类型和字符编码.如果在提交响应后调用此方法，则此方法无效.
	 * 如果在调用getWriter之后或在提交响应之后调用它，则不会设置响应的字符编码.
	 * The default behavior of this method is to call setContentType(String type)
     * on the wrapped response object.
     */

    public void setContentType(String type) {
	this.response.setContentType(type);
    }

    /**
	 * 返回用于此响应中发送的MIME正文的内容类型.
	 * 在提交响应之前，必须使用setContentType指定正确的内容类型.
	 * 如果未指定内容类型，则此方法返回null.
	 * 如果已指定内容类型，并且已显式或隐式指定字符编码，如getCharacterEncoding或getWriter中所述，则返回的字符串中包含charset参数.如果未指定字符编码，则省略charset参数.
	 *
	 * The default behavior of this method is to return getContentType()
     * on the wrapped response object.
     *
     * @since 2.4
     */

    public String getContentType() {
	return this.response.getContentType();
    }
    
    /**
	 * 设置响应正文的首选缓冲区大小.Servlet容器将使用至少与请求大小相同的缓冲区.实际使用的缓冲区大小可以使用getBufferSize.
	 * 更大的缓冲区允许在实际发送任何内容之前写入更多内容，从而为Servlet提供更多时间来设置适当的状态代码和标头.
	 * 较小的缓冲区减少了服务器内存负载，并允许客户端更快地开始接收数据.
	 * 必须在写入任何响应正文内容之前调用此方法.如果已写入内容或已提交response，则此方法将抛出IllegalStateException.
	 * The default behavior of this method is to call setBufferSize(int size)
     * on the wrapped response object.
     */
    public void setBufferSize(int size) {
	this.response.setBufferSize(size);
    }
    
    /**
	 * 返回用于响应的实际缓冲区大小.
	 * 如果不使用缓冲，则此方法返回0.
	 * The default behavior of this method is to return getBufferSize()
     * on the wrapped response object.
     */
    public int getBufferSize() {
	return this.response.getBufferSize();
    }

    /**
	 * 强制将缓冲区中的任何内容写入客户端.对此方法的调用会自动提交响应，这意味着将写入状态代码和标头.
	 * The default behavior of this method is to call flushBuffer()
     * on the wrapped response object.
     */

    public void flushBuffer() throws IOException {
	this.response.flushBuffer();
    }
    
    /**
	 * 返回一个布尔值，指示是否已提交响应.已提交的响应已写入其状态代码和标头.
	 * The default behavior of this method is to return isCommitted()
     * on the wrapped response object.
     */
    public boolean isCommitted() {
	return this.response.isCommitted();
    }

    /**
	 * 清除缓冲区中存在的所有数据以及状态代码和标头.如果响应已提交，此方法将抛出IlleglaStateException.
	 * The default behavior of this method is to call reset()
     * on the wrapped response object.
     */

    public void reset() {
	this.response.reset();
    }
    
    /**
	 * 清除响应中基础缓冲区的内容，而不清除标头或状态码.如果响应已提交，此方法将抛出IlleglaStateException.
	 * The default behavior of this method is to call resetBuffer()
     * on the wrapped response object.
     */
     
    public void resetBuffer() {
	this.response.resetBuffer();
    }
    
    /**
	 * 在response未提交时，设置response的locale.
	 * 如果尚未使用setContentType或setCharacterEncoding设置字符集、getWriter尚未被调用、response尚未被提交，它还会为区域设置适当的响应字符编码.
	 * 可以重复调用此方法来更改区域设置和字符编码.如果在提交响应后调用该方法，则该方法无效.
	 * 如果在使用字符集规范调用setContentType之后、调用setCharacterEncoding之后、调用了getWriter之后，或者在响应被提交之后调用，它不会设置响应的字符编码.
	 * 如果协议提供了一种方法，容器必须将用于servlet响应的编写器的区域设置和字符编码传递给客户端.
	 * 在HTTP的情况下，语言环境通过Content-Language报头进行通信，字符编码作为文本媒体类型的Content-Type报头的一部分.
	 * 请注意，如果Servlet没有指定内容类型，则字符编码不能通过HTTP头进行通信.但是，它仍然用于对通过Servlet响应的编写器写入的文本进行编码.
	 *
	 * The default behavior of this method is to call setLocale(Locale loc)
     * on the wrapped response object.
     */

    public void setLocale(Locale loc) {
	this.response.setLocale(loc);
    }
    
    /**
	 * 返回使用setLocale指定的区域设置.setLocale在response提交之后不会生效.
	 * 如果没有指定locale，返回容器默认的locale.
	 * The default behavior of this method is to return getLocale()
     * on the wrapped response object.
     */
    public Locale getLocale() {
	return this.response.getLocale();
    }


}





